#pragma once

#include <QObject>
#include <QPointer>
#include <QMetaObject>
#include <QString>
#include <functional>
#include <tuple>

namespace base::tasking {

/**
 * @brief 线程安全的任务回调结构
 *
 * 设计要点:
 * - 使用 QPointer 保护线程上下文对象生命周期
 * - 使用 QMetaObject::invokeMethod 确保回调在正确线程执行
 * - 支持成功、失败、取消三种回调
 * - 所有回调都是可选的(std::function 可为空)
 *
 * @tparam T 成功回调的数据类型
 */
template<typename T>
struct TaskCallbacks {
    std::function<void(const T&)> onSuccess;
    std::function<void(const QString&)> onError;
    std::function<void()> onCancel;
    QPointer<QObject> context = nullptr;  // 线程上下文保护

    /**
     * @brief 线程安全地调用成功回调
     *
     * @param value 成功返回值
     *
     * 如果设置了 context,会通过 QMetaObject::invokeMethod 在目标线程执行。
     * 使用 QPointer 检查 context 是否已被销毁。
     *
     * 关键安全措施: 在调用前复制所有成员,避免异步 lambda 引用已销毁的 this
     */
    void callOnSuccess(const T& value) const {
        if (onSuccess) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onSuccess;
            auto ctx = context;
            invokeCallback([callback, value]() {
                callback(value);
            }, ctx);
        }
    }

    /**
     * @brief 线程安全地调用错误回调
     *
     * @param errorMessage 错误消息
     */
    void callOnError(const QString& errorMessage) const {
        if (onError) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onError;
            auto ctx = context;
            invokeCallback([callback, errorMessage]() {
                callback(errorMessage);
            }, ctx);
        }
    }

    /**
     * @brief 线程安全地调用取消回调
     */
    void callOnCancel() const {
        if (onCancel) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onCancel;
            auto ctx = context;
            invokeCallback([callback]() {
                callback();
            }, ctx);
        }
    }

private:
    /**
     * @brief 内部辅助方法 - 线程安全地调用回调
     *
     * @param callback 要执行的回调函数
     * @param ctx 线程上下文(已复制,不依赖 this)
     *
     * 如果有 context:
     * - 使用 QPointer 检查 context 是否存活
     * - 通过 QMetaObject::invokeMethod 在目标线程执行
     * - 使用 Qt::QueuedConnection 确保异步执行
     *
     * 如果没有 context:
     * - 直接在当前线程执行(同步调用)
     */
    static void invokeCallback(std::function<void()> callback, QPointer<QObject> ctx) {
        if (ctx) {
            // 检查 context 是否仍然存活
            if (QPointer<QObject> guard(ctx); guard) {
                QMetaObject::invokeMethod(
                    ctx,
                    [callback = std::move(callback)]() {
                        if (callback) {
                            callback();
                        }
                    },
                    Qt::QueuedConnection);
            }
        } else {
            // 没有 context,直接执行
            if (callback) {
                callback();
            }
        }
    }
};

/**
 * @brief 特化版本 - void 类型的成功回调(无返回值)
 */
template<>
struct TaskCallbacks<void> {
    std::function<void()> onSuccess;
    std::function<void(const QString&)> onError;
    std::function<void()> onCancel;
    QPointer<QObject> context = nullptr;

    void callOnSuccess() const {
        if (onSuccess) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onSuccess;
            auto ctx = context;
            invokeCallback([callback]() {
                callback();
            }, ctx);
        }
    }

    void callOnError(const QString& errorMessage) const {
        if (onError) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onError;
            auto ctx = context;
            invokeCallback([callback, errorMessage]() {
                callback(errorMessage);
            }, ctx);
        }
    }

    void callOnCancel() const {
        if (onCancel) {
            // 复制回调函数和上下文,避免悬垂指针
            auto callback = onCancel;
            auto ctx = context;
            invokeCallback([callback]() {
                callback();
            }, ctx);
        }
    }

private:
    static void invokeCallback(std::function<void()> callback, QPointer<QObject> ctx) {
        if (ctx) {
            if (QPointer<QObject> guard(ctx); guard) {
                QMetaObject::invokeMethod(
                    ctx,
                    [callback = std::move(callback)]() {
                        if (callback) {
                            callback();
                        }
                    },
                    Qt::QueuedConnection);
            }
        } else {
            if (callback) {
                callback();
            }
        }
    }
};

} // namespace base::tasking
